/**
 * Class: Table
 *
 * Purpose: 
 *
 * @author Ken Scott
 */
package org.openfantasia.util.misc;

import org.openfantasia.util.FileUtils;
import org.openfantasia.util.LogUtils;
import org.openfantasia.util.Utils;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;


public class Table {

	public static final String FLIRT_CATALOG_TSV_URL = "http://www.flirtcatalog.org/productfeed.aspx?affiliateid=1028";


	public static void main(String[] args) {
		try {
			File file = FileUtils.createLocalFile("domains", "domain-list.txt");
			List<String> lines = FileUtils.readLinesFromFile(file);
			Table table = new Table();
			table.readTabSeparatedValues(lines, true);
			LogUtils.log(table.toString());
		}
		catch (IOException e) {
			e.printStackTrace();
		}
	}


	protected List<String> columnHeaders = new ArrayList<String>();

	protected List<Map<String, String>> rows = new ArrayList<Map<String, String>>();

	protected boolean hasColumnHeaders = false;


	public static Table loadTable(File file) throws IOException {
		// Get twitter table
		List<String> lines = FileUtils.readLinesFromFile(file);
		return readLines(lines);
	}


	public static Table loadTable(InputStream stream) throws IOException {
		// Get twitter table
		List<String> lines = FileUtils.readLinesFromStream(stream);
		return readLines(lines);
	}


	private static Table readLines(List<String> lines) {
		lines = (List<String>) Utils.removeDuplicates(lines);
		lines = Utils.removeCommentBlocks(lines);
		lines = Utils.removeCommentLines(lines);
		lines = Utils.removeEmptyLines(lines);

		for(int i = 0; i < lines.size(); i++) {
			lines.set(i, Utils.removeComments(lines.get(i)));
		}

		return new Table(lines, true);
	}


	public Table() {
	}


	public Table(List<String> columnHeaders) {
		setColumnHeaders(columnHeaders);
	}


	public Table(String... columnHeaders) {
		setColumnHeaders(Arrays.asList(columnHeaders));
	}


	public Table(List<String> lines, boolean hasColumnHeaders) {
		readSeparatedValues(lines, "\t", hasColumnHeaders);
	}


	public void readTabSeparatedValues(List<String> lines, boolean hasColumnHeaders) {
		readSeparatedValues(lines, "\t", hasColumnHeaders);
	}


	public void readCommaSeparatedValues(List<String> lines, boolean hasColumnHeaders) {
		readSeparatedValues(lines, ",", hasColumnHeaders);
	}


	public void readSeparatedValues(List<String> lines, String separator, boolean hasColumnHeaders) {
		this.hasColumnHeaders = hasColumnHeaders;
		Iterator<String> lineIter = lines.iterator();

		if (hasColumnHeaders) {
			if (lineIter.hasNext()) {
				String line = lineIter.next();
				String[] values = line.split("\\" + separator);
				columnHeaders.addAll(Arrays.asList(values));
			}
		}

		while (lineIter.hasNext()) {
			String line = lineIter.next();
			try {
				String[] values = line.split("\\" + separator);
				Map<String, String> row = new TreeMap<String, String>();
				if (!columnHeaders.isEmpty()) {
					int i = 0;
					for (String key : columnHeaders) {
						row.put(key, values[i++]);
					}
				}
				else {
					columnHeaders.clear();
					String si;
					for (int i = 0; i < values.length; i++) {
						si = Integer.toString(i);
						columnHeaders.add(si);
						row.put(si, values[i]);
					}
				}
				rows.add(row);
			}
			catch (ArrayIndexOutOfBoundsException x) {
				LogUtils.log("ArrayIndexOutOfBoundsException:  " + line);
			}
		}
	}


	public List<String> getColumnHeaders() {
		return columnHeaders;
	}


	public void setColumnHeaders(List<String> columnHeaders) {
		this.hasColumnHeaders = true;
		this.columnHeaders = new ArrayList<String>(columnHeaders);
	}


	public void addColumnHeader(String header) {
		this.hasColumnHeaders = true;
		this.columnHeaders.add(header);
	}


	public List<Map<String, String>> getRows() {
		return rows;
	}


	public void setRows(List<Map<String, String>> rows) {
		this.rows = rows;
	}


	public void addRow(Map<String, String> row) {
		this.rows.add(row);
	}


	public String toCommaSeparatedValues() {
		return toSeparatedValues(",");
	}


	public String toTabSeparatedValues() {
		return toSeparatedValues("\t");
	}


	public String toSeparatedValues(String separator) {
		StringBuffer result = new StringBuffer();

		if (hasColumnHeaders) {
			Iterator<String> columnIterator = columnHeaders.iterator();
			while (columnIterator.hasNext()) {
				String value = columnIterator.next();
				result.append(value);
				if (columnIterator.hasNext()) {
					result.append(separator);
				}
			}
			result.append("\n");
		}

		for (Map<String, String> line : rows) {
			Iterator<String> columnIterator = columnHeaders.iterator();
			while (columnIterator.hasNext()) {
				String key = columnIterator.next();
				result.append(line.get(key));
				if (columnIterator.hasNext()) {
					result.append(separator);
				}
			}
			result.append("\n");
		}

		return result.toString();
	}


	public String toString() {
		StringBuffer result = new StringBuffer();

		if (hasColumnHeaders) {
			Iterator<String> columnIterator = columnHeaders.iterator();
			result.append("HEADERS: ");
			while (columnIterator.hasNext()) {
				String value = columnIterator.next();
				result.append(value);
				if (columnIterator.hasNext()) {
					result.append(", ");
				}
			}
			result.append("\n");
		}

		for (Map<String, String> line : rows) {
			Iterator<String> columnIterator = columnHeaders.iterator();
			while (columnIterator.hasNext()) {
				String key = columnIterator.next();
				result.append(key + "=");
				result.append(line.get(key));
				if (columnIterator.hasNext()) {
					result.append(", ");
				}
			}
			result.append("\n");
		}

		return result.toString();
	}
}